unit Vector;

interface

uses Mathematic, SysUtils;

type
  TVectorData = array [0..2] of TFloat;
  TVectorDataPointer = ^TVectorData;
  TVector3f = class
  private
    aData: TVectorData;
    aDataPointer: TVectorDataPointer;
    procedure SetX(paValue: TFloat);
    function GetX: TFloat;
    procedure SetY(paValue: TFloat);
    function GetY: TFloat;
    procedure SetZ(paValue: TFloat);
    function GetZ: TFloat;
    procedure SetData(paData: TVectorData);
    procedure SetIndexData(I:Integer; Value: TFloat);
    function GetIndexData(I:Integer): TFloat;
  public
    constructor Create;overload;
    constructor Create(paX, paY, paZ: TFloat);overload;
    constructor CreateCopy(paVector: TVector3f);
    destructor Destroy;override;
    procedure MakeCopy(paVector: TVector3f);
    procedure SetXYZ(paX, paY, paZ: TFloat);
    function IsEqual(paVector: TVector3f): Boolean; overload;
    function IsEqual(paVector: TVector3f; paEpsilon: TFloat): Boolean; overload;
    function Add(paVector: TVector3f): TVector3f;
    function AddSelf(paVector: TVector3f): TVector3f;
    function Subtract(paVector: TVector3f): TVector3f;
    function SubtractSelf(paVector: TVector3f): TVector3f;
    function Multiply(paScalar: TFloat): TVector3f;
    function MultiplySelf(paScalar: TFloat): TVector3f;
    function Divide(paScalar: TFloat): TVector3f;
    function DivideSelf(paScalar: TFloat): TVector3f;
    function Normalize: TVector3f;
    function NormalizeSelf: TVector3f;
    function Scale(paLength: TFloat): TVector3f;
    function ScaleSelf(paLength: TFloat): TVector3f;
    function Truncate(paLength: TFloat): TVector3f;
    function TruncateSelf(paLength: TFloat): TVector3f;
    function Length: TFloat;
    function Distance(paVector: TVector3f): TFloat;
    function DotProduct(paVector: TVector3f): TFloat;
    function CrossProduct(paVector: TVector3f): TVector3f;
    function SaveToFile(var F: Text): Boolean; virtual;
    function LoadFromFile(var F: Text): Boolean; virtual;
    property X: TFloat read GetX write SetX;
    property Y: TFloat read GetY write SetY;
    property Z: TFloat read GetZ write SetZ;
    property Data: TVectorData read aData write aData;
    property DataPointer: TVectorDataPointer read aDataPointer write aDataPointer;
    property Value[I: Integer]: TFloat read GetIndexData write SetIndexData;default;
  end;
  TVector = TVector3f;

implementation

procedure TVector3f.SetX(paValue: TFloat);
begin
    aData[0] := paValue;
end;

function TVector3f.GetX: TFloat;
begin
    Result := aData[0];
end;

procedure TVector3f.SetY(paValue: TFloat);
begin
    aData[1] := paValue;
end;

function TVector3f.GetY: TFloat;
begin
    Result := aData[1];
end;

procedure TVector3f.SetZ(paValue: TFloat);
begin
    aData[2] := paValue;
end;

function TVector3f.GetZ: TFloat;
begin
    Result := aData[2];
end;

procedure TVector3f.SetData(paData: TVectorData);
var I: Integer;
begin
    for I := 0 to 2 do begin
        aData[I] := paData[I];
    end;
end;

procedure TVector3f.SetIndexData(I: Integer; Value: TFloat);
begin
    aData[I] := Value;
end;

function TVector3f.GetIndexData(I: Integer): TFloat;
begin
    Result := aData[I];
end;

constructor TVector3f.Create;
begin
    inherited Create;
    X := 0.0;
    Y := 0.0;
    Z := 0.0;
    aDataPointer := @aData;
end;

constructor TVector3f.Create(paX, paY, paZ: TFloat);
begin
    inherited Create;
    X := paX;
    Y := paY;
    Z := paZ;
    aDataPointer := @aData;
end;

constructor TVector3f.CreateCopy(paVector: TVector3f);
begin
    inherited Create;
    SetData(paVector.aData);
    aDataPointer := @aData;
end;

destructor TVector3f.Destroy;
begin
    inherited Destroy;
end;

procedure TVector3f.MakeCopy(paVector: TVector3f);
begin
    SetData(paVector.aData);
    aDataPointer := @aData;
end;

procedure TVector3f.SetXYZ(paX, paY, paZ: TFloat);
begin
    X := paX;
    Y := paY;
    Z := paZ;
end;

function TVector3f.IsEqual(paVector: TVector3f): Boolean;
begin
    Result := (X = paVector.X) and (Y = paVector.Y) and (Z = paVector.Z);
end;

function TVector3f.Add(paVector: TVector3f) : TVector3f;
begin
    Result := TVector3f.Create(X + paVector.X, Y + paVector.Y, Z + paVector.Z);
end;

function TVector3f.AddSelf(paVector: TVector3f) : TVector3f;
begin
    X := X + paVector.X;
    Y := Y + paVector.Y;
    Z := Z + paVector.Z;
    Result := self;
end;

function TVector3f.Subtract(paVector: TVector3f) : TVector3f;
begin
    Result := TVector3f.Create(X - paVector.X, Y - paVector.Y, Z - paVector.Z);
end;

function TVector3f.SubtractSelf(paVector: TVector3f) : TVector3f;
begin
    X := X - paVector.X;
    Y := Y - paVector.Y;
    Z := Z - paVector.Z;
    Result := self;
end;

function TVector3f.Multiply(paScalar: TFloat) : TVector3f;
begin
    Result := TVector3f.Create(X * paScalar, Y * paScalar, Z * paScalar);
end;

function TVector3f.MultiplySelf(paScalar: TFloat) : TVector3f;
begin
    X := X * paScalar;
    Y := Y * paScalar;
    Z := Z * paScalar;
    Result := self;
end;

function TVector3f.Divide(paScalar: TFloat) : TVector3f;
var Reciprocity: TFloat;
begin
    Reciprocity := 1 / paScalar;
    Result := TVector3f.Create(X * Reciprocity, Y * Reciprocity, Z * Reciprocity);
end;

function TVector3f.DivideSelf(paScalar: TFloat) : TVector3f;
var Reciprocity: TFloat;
begin
    Reciprocity := 1 / paScalar;
    X := X * Reciprocity;
    Y := Y * Reciprocity;
    Z := Z * Reciprocity;
    Result := self;
end;

function TVector3f.Normalize: TVector3f;
begin
    if Length <> 0.0 then Result := Divide(Length)
    else Result := TVector3f.Create(0.0, 0.0, 0.0);
end;

function TVector3f.NormalizeSelf: TVector3f;
begin
    if Length <> 0.0 then Result := DivideSelf(Length)
    else Result := self;
end;

function TVector3f.Scale(paLength: TFloat): TVector3f;
begin
    Result := TVector.CreateCopy(self).NormalizeSelf.MultiplySelf(paLength);
end;

function TVector3f.ScaleSelf(paLength: TFloat): TVector3f;
begin
    Result := NormalizeSelf.MultiplySelf(paLength)
end;

function TVector3f.Truncate(paLength: TFloat): TVector3f;
begin
    if Length <= paLength then
        Result := TVector.CreateCopy(self)
    else
        Result := TVector.CreateCopy(self).NormalizeSelf.MultiplySelf(paLength);
end;

function TVector3f.TruncateSelf(paLength: TFloat): TVector3f;
begin
    if Length <= paLength then
        Result := self
    else
        Result := NormalizeSelf.MultiplySelf(paLength)
end;

function TVector3f.Length: TFloat;
begin
    Result := Sqrt(X * X + Y * Y + Z * Z);
end;

function TVector3f.Distance(paVector: TVector3f): TFloat;
var Vector: TVector;
begin
    Vector := Subtract(paVector);
    Result := Abs(Vector.Length);
    Vector.Free;
end;

function TVector3f.IsEqual(paVector: TVector3f; paEpsilon: TFloat): Boolean;
begin
    Result := Distance(paVector) <= paEpsilon;
end;

function TVector3f.DotProduct(paVector: TVector3f): TFloat;
begin
    Result := X * paVector.X + Y * paVector.Y + Z * paVector.Z;
end;

function TVector3f.CrossProduct(paVector: TVector3f): TVector3f;
begin
    Result := TVector3f.Create(Y * paVector.Z - Z * paVector.Y,
                               Z * paVector.X - X * paVector.Z,
                               X * paVector.Y - Y * paVector.X);

end;

function TVector3f.SaveToFile(var F: Text): Boolean;
begin
    FloatToFile(X, F);
    FloatToFile(Y, F);
    FloatToFile(Z, F);
end;

function TVector3f.LoadFromFile(var F: Text): Boolean;
begin
    FloatFromFile(aData[0], F);
    FloatFromFile(aData[1], F);
    FloatFromFile(aData[2], F);
end;

end.
